#include "common_util.h"

#include "os_adapter.h"

/**
 * @brief 使用滴答定时器进行延时, 仅在初始化时使用, 严禁在应用层中调用
 *
 * @param ms 延时的毫秒数
 */
void common_util_delay_ms(uint32_t ms)
{
    uint32_t cur_tick = OS_Adapter_GetCurrentTick();

    while (OS_Adapter_GetCurrentTick() - cur_tick < ms);
}

/**
 * @brief  获取当前的滴答定时器值
 *
 * @return uint32_t  当前的滴答定时器值
 */
uint32_t common_util_get_tick(void) { return OS_Adapter_GetCurrentTick(); }

/**
 * @brief 微秒级精确延时函数，基于60MHz系统时钟
 *
 * @param us 延时的微秒数
 * @note    此函数使用循环计数实现，适用于短时间精确延时
 *          在60MHz时钟下，每微秒需要约60个时钟周期
 *          考虑到循环开销，实际循环次数会根据编译器优化调整
 */
void common_util_delay_us(uint32_t us)
{
    /* 在60MHz时钟下，每微秒约需要60个时钟周期
     * 考虑到循环指令的开销（实验验证10个周期最为准确），
     * 设置循环计数为15次/微秒（60/10=6）
     */
    uint32_t volatile count = us * 6;

    while (count--) {
        /* 空循环，编译器不会优化掉volatile变量 */
        __asm("nop"); /* 插入NOP指令确保时序准确 */
    }
}

/**
 * @brief 气压值转换为信号值
 *
 * @param   air_pressure    气压值(KPa)
 * @return  uint8_t         信号值
 */
uint8_t common_util_air_pressure_to_signal(uint32_t air_pressure)
{
    const uint8_t MIN_AIR_PRESSURE = 65;
    const uint8_t MAX_AIR_PRESSURE = 192;

    if (air_pressure < MIN_AIR_PRESSURE || air_pressure > MAX_AIR_PRESSURE) {
        return 0x00;
    }

    /*
        注意：当前不考虑0.5KPa气压的情况，因为CPS121气压传感器的值返回的是整形
    */
    uint8_t ans = 2 * air_pressure - 129;
    return ans;
}

/**
 * @brief 计算CRC8校验值
 *
 * @param   data    指向要计算CRC8的数据的指针
 * @param   length  数据的长度（字节数）
 * @return  uint8_t 返回计算出的CRC8校验值
 */
uint8_t common_util_crc8_calculate(const uint8_t *data, uint16_t length)
{
    uint8_t       crc        = 0x00;           // 初始化CRC为0
    const uint8_t polynomial = 0x31;           // CRC-8/Maxim 多项式

    for (uint16_t i = 0; i < length; ++i) {
        crc ^= data[i];                        // 将当前字节与CRC进行异或操作
        for (uint8_t bit = 0; bit < 8; ++bit) {
            if (crc & 0x80) {                  // 如果最高位是1
                crc = (crc << 1) ^ polynomial; // 左移并异或多相式
            }
            else {
                crc <<= 1;                     // 否则只左移
            }
            crc &= 0xFF;                       // 确保CRC保持在一个字节内
        }
    }

    return crc;
}
